package com.coolingme.web.provider;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * 默认身份认证(用户名密码)<br>
 * 验证用户身份的合法性<br>
 * 根据用户输入的用户名查找用户信息，将查询到的密码和输入的密码比较
 *
 * @author wangyue
 * @date 2020-01-05 15:43:28
 */
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {

    /**
     * AuthenticationProvider:用于认证的，可以通过实现这个接口来定制我们自己的认证逻辑
     */
    @Autowired
    @Qualifier("myUserDetailsService")
    private UserDetailsService userDetailsService;

    /**
     * 注入密码加密方式
     *
     * @return 加密工具
     */
    @Bean(name = "bCryptPasswordEncoder")
    public PasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 进行身份认证
     *
     * @param authentication 账号密码
     * @return Authentication 通过账号密码查询出的用户信息
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // 获取用户输入的用户名和密码
        String account = authentication.getName();
        String password = authentication.getCredentials().toString();
        // 获取封装用户信息的对象
        UserDetails userDetails = userDetailsService.loadUserByUsername(account);

        // 未查询到用户
        if (userDetails == null) {
            throw new UsernameNotFoundException("user:" + account + " is null");
        }

        // 进行密码的比对
        boolean isPasswordMatch = bCryptPasswordEncoder().matches(password, userDetails.getPassword());
        if (isPasswordMatch) {
            // 将权限信息也封装到Authentication中
            return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
        } else {
            // 密码不匹配
            throw new BadCredentialsException("user:" + account + " password is not match");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

}
